import {Scene ,PerspectiveCamera, HemisphereLight, Clock,DirectionalLight,WebGLRenderer, Color,
    PMREMGenerator,sRGBEncoding, AnimationMixer, Object3D,Vector3,

}from '../libs/three137/three.module.js';
    import { RGBELoader } from '../libs/three137/RGBELoader.js';
import { LoadingBar } from '../libs/LoadingBar.js';
import { CubeTexture, CubeTextureLoader, IcosahedronGeometry, Mesh, MeshBasicMaterial } from '../libs/three137/three.module.js';
import { OrbitControls } from '../libs/three137/OrbitControls.js';
import { Plane } from './Plane.js';
import { urls } from '../assets/store.js';
import { Obstacles } from './Obstacles.js';
import { SFX } from './SFX.js';
const { PI, sin , cos , random } =Math
class Game{
	constructor(){
        this.spaceKey = false ;
		const container = document.createElement( 'div' );
		document.body.appendChild( container );
        this.pause = false;
        
        this.loadingBar = new LoadingBar();
        this.loadingBar.visible = false;

        this.clock = new Clock();

		// this.assetsPath = '../../assets/';
        
		this.camera = new PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 100 );
        this.camera.position.set( -4.37, 0, -4.75 ); // 相机相对父级的偏移
        this.camera.lookAt(0, 0, 6);

        this.cameraController = new Object3D();
        this.cameraController.add(this.camera);
        this.cameraTarget = new Vector3(0,0,6);
        
		this.scene = new Scene();
        this.scene.add(this.cameraController);

		const ambient = new HemisphereLight(0xffffff, 0xbbbbff, 1);
        this.scene.add(ambient);
			
		this.renderer = new WebGLRenderer({ antialias: true, alpha: true } );
		this.renderer.setPixelRatio( window.devicePixelRatio );
		this.renderer.setSize( window.innerWidth, window.innerHeight );
        this.renderer.outputEncoding = sRGBEncoding;
		container.appendChild( this.renderer.domElement );
        this.setEnvironment();
        
        this.load();


        this.controller = new OrbitControls(this.camera, this.renderer.domElement)
		
		window.addEventListener('resize', this.resize.bind(this) );
        window.addEventListener('pointerdown', this.pointerDown.bind(this))
        window.addEventListener('pointerup', this.pointerUp.bind(this))
        // keydown 任意键都会触发 keypress只有会触发字符值时会触发, 并且都不存在持续触发
        window.addEventListener('keyup', this.keyUp.bind(this))
        window.addEventListener('keydown', this.keyDown.bind(this))
        // window.addEventListener('keypress', this.keyDown.bind(this))
        window.addEventListener('touchstart', this.touchStart.bind(this))
        window.addEventListener('touchend', this.touchEnd.bind(this))
        this.active = false ;
        let btn = document.getElementById('playBtn') ;
        this.startBtn =btn ;
        btn.addEventListener('pointerdown', this.startGame )
	}

    startGame = ()=>{ 
        this.sfx.stop('gameover')
        this.controller.enabled =false ;
        const gameover = this.gameoverPane || document.getElementById('gameover');
        const instructions  =document.getElementById('instructions')
        instructions.style.display ='none' ;
        this.startBtn.style.display= 'none' ;

        //
        gameover.style.display = 'none';
        instructions.style.display = 'none';
        // 重置 分数 命
        this.score = 0;
        this.lives = 5;

        let elm = document.getElementById('score');
        elm.innerHTML = this.score;
        
        elm = document.getElementById('lives');
        elm.innerHTML = this.lives;
        // 重置场景状态
        this.plane.reset();
        this.obstacles.reset();

       
        this.active =true ;
        this.sfx.play('engine')

    }
    pauseOrContinueGame =(val)=> { 
        this.pause = val;
        if(val) {this.clock.stop() 
        this.sfx.pause('engine');
        }
        else {this.clock.start(); 
            this.sfx.play('engine');
        
        }
    }
	
    resize(){
        this.camera.aspect = window.innerWidth / window.innerHeight;
    	this.camera.updateProjectionMatrix();
    	this.renderer.setSize( window.innerWidth, window.innerHeight ); 
    }

    setEnvironment(){
        const loader = new RGBELoader() ;
        const pmremGenerator = new PMREMGenerator( this.renderer );
        pmremGenerator.compileEquirectangularShader();
        
        loader.load( urls.field_sky_hdr, ( texture ) => {
          const envMap = pmremGenerator.fromEquirectangular( texture ).texture;
          pmremGenerator.dispose();

          this.scene.environment = envMap;
        //   this.scene.background = envMap;

        }, undefined, (err)=>{
            console.error( err.message );
        } );
    }
    
	load(){
        this.loading = true ;
        this.loadingBar.visible = true ;
        this.plane = new Plane(this)
        this.obstacles = new Obstacles(this);
        this.loadSkybox()
        this.loadSFX()


    }

    loadSkybox(){
        this.scene.background = new CubeTextureLoader( ).load(
            [
         urls.paintedskyBox.px , 
         urls.paintedskyBox.nx , 
         urls.paintedskyBox.py , 
         urls.paintedskyBox.ny , 
         urls.paintedskyBox.pz , 
         urls.paintedskyBox.nz , 
        ] )
    }		

    loadSFX(){ 
        this.sfx = new SFX(this.camera,) ;
        this.sfx.load('explosion',false,.8) ;
        this.sfx.load('engine', true) ;
        this.sfx.load('gliss', false, .8) ;
        this.sfx.load('gameover', false , .8) ;
        this.sfx.load('bonus', false , 1) ;
    }

    gameover(){ 
        this.active = false ;
        const gameover= this.gameoverPane || document.getElementById('gameover');
        this.gameoverPane = gameover ;
    
        gameover.style.display ='block' ;
        
        this.startBtn.style.display= 'block' ;
        console.log('over', this.obstacles);
        this.sfx.stopAll()
        this.sfx.play('gameover')
        this.controller.enabled =true ;


    }
    inScore(){
        this.score++;
        let ele = document.getElementById('score');
        ele.innerHTML = this.score;
        this.sfx.stop('gliss') ;
        this.sfx.play('gliss') ;
    }
    decLives(){ 
        this.lives-- ;
        let ele = document.getElementById('lives');
        ele.innerHTML = this.lives;
        this.sfx.stop('explosion')
        this.sfx.play('explosion')
        if(!this.lives){ setTimeout( this.gameover.bind(this) , 500)}
        
    }
    touchStart(e){ 
        e.preventDefault() ;
        this.spaceKey = true ;

    }
    touchEnd(e){ 
        e.preventDefault() ;
        this.spaceKey = false ;

    }
    pointerDown(e){ 
        switch (e.button) {
            case 0: // 左键
                this.spaceKey = true ;
                break;
        
            default:
                break;
        }
        // console.log(e);
    }
    poninterMove(e){ 
        
    }
    pointerUp(e){ 
        switch (e.button) {
            case 0: // 左键
                this.spaceKey = false ;
                break;
        
            default:
                break;
        }
    }
    keyUp(e){ 
        // console.log(e);// keycode 32 key code 都是按键名
        switch (e.code) {
            case 'Space':
                this.spaceKey = false  ;
                break;
        
            default:
                break;
        }
    }
    keyDown(e){ 

        switch (e.code) {
            case 'Space':
                this.spaceKey = true ;
                break;
            case 'Escape': 
                this.pauseOrContinueGame(!this.pause);
                break;
            default:
                break;
        }
    }

    updateCamera(){
                if(this.plane){ 
                    let pos = this.plane.position ;
                    this.cameraController.position.set(pos.x,0,pos.z) ; // 让相机在y分量上固定不跟随目标
                    this.camera.lookAt(pos.x,pos.y,pos.z+6)
                }
    }
    

	render(t) {
        if(this.loading){ 
            if(this.plane.ready && this.obstacles.ready){ 
                this.loading = false  ;
                this.loadingBar.visible = false ;
            }else { 
                return
            }
        }
        if  (this.pause)  return ;// 渲染虽然停了但是这个时间没有停

        let dt = this.clock.getDelta() // getElapsedTime 方法其实就会调用这个方法 所以直接
        const time = this.clock.elapsedTime;
        this.plane.update(time)
        if(this.active){
            this.updateCamera()
            this.obstacles.update(this.plane.position, dt)
        }

        this.renderer.render( this.scene, this.camera );

    }
}

export { Game };